package com.ddwl.funds.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.ddwl.common.constant.BaseEnum;
import com.ddwl.common.constant.OrderEnum;
import com.ddwl.common.constant.OrderTypeEnum;
import com.ddwl.common.constant.PaymentEnum;
import com.ddwl.common.exception.ParamException;
import com.ddwl.common.exception.PayException;
import com.ddwl.funds.constant.AlipayConfig;
import com.ddwl.funds.constant.FundsConstant;
import com.ddwl.funds.dao.AliPayConfigDao;
import com.ddwl.funds.dao.OrderAliPayDao;
import com.ddwl.funds.dao.OrderAliPayRefundsDao;
import com.ddwl.funds.dao.OrderRefundsDao;
import com.ddwl.funds.dao.model.*;
import com.ddwl.funds.service.bo.AlipayRefundBo;
import com.ddwl.schema.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.Map;

/**
 * 类AliPayServer.java的实现描述：支付宝支付
 *
 * @author zach
 * @Date :2020-09-26 15:37.
 */
@Slf4j
@Service
@RefreshScope
public class AliPayServer {

    @Resource
    private OrderAliPayDao orderAliPayDao;
    @Resource
    private OrderAliPayRefundsDao orderAliPayRefundsDao;
    @Resource
    private AliPayConfigDao aliPayConfigDao;
    @Resource
    private PaymentServer paymentServer;
    @Resource
    private OrderRefundsDao orderRefundsDao;
    @Resource
    private RabbitTemplate rabbitTemplate;
    /**
     * 支付成功状态
     */
    private String paySuccess = "TRADE_SUCCESS";
    private String paySuccessCode = "10000";
    @Value("${spring.profiles.active}")
    private String active;
    @Value("${ddwl.test.payamount}")
    private String testPayAmount;
    /**
     * 调用阿里SDK生成的签名
     * 阿里官方文档地址 https://docs.open.alipay.com/api_1/alipay.trade.app.pay
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class,propagation= Propagation.NOT_SUPPORTED)
    public String aliPaymentSdk(OrderPay orderPay) {
        OrderAliPay oldPay = orderAliPayDao.nowPay(orderPay.getOrderId());
        //如果该单号查到支付信息去支付宝主动查询下当前订单是否支付完成
        if(oldPay!=null){
            oldPay = queryOrderPayStatus(oldPay);
            ParamException.isTrue(paySuccess.equals(oldPay.getTradeStatus()),"订单已支付完成请勿重复支付");
        }
        //获取应用支付宝配置
        AliPayConfig aliPayConfig = aliPayConfigDao.getAliPayConfigByProduct(orderPay.getPayProduct());
        ParamException.isNull(aliPayConfig, "未找到该平台的支付宝配置信息");
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.PAY_URL, aliPayConfig.getAppId(), aliPayConfig.getAppKey(), AlipayConstants.FORMAT_JSON, AlipayConstants.CHARSET_UTF8, aliPayConfig.getAliPub(), AlipayConstants.SIGN_TYPE_RSA2);
        String orderString = "";
        //创建调用支付支付宝支付信息
        AlipayTradeAppPayRequest aliRequest = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setTotalAmount(orderPay.getAmount().setScale(2).toString());
        model.setSubject(orderPay.getSubject());
        model.setOutTradeNo(orderPay.getOrderId());
        Instant expirationTime = DateUtil.addMinutes(Instant.now(),30);
        Instant orderExpirationTime = orderPay.getExpirationTime();
        if(expirationTime.isBefore(orderExpirationTime)){
            model.setTimeExpire(DateUtil.formatDate(expirationTime, DateUtil.DATE_TIME_FORMAT));
        }else {
            model.setTimeExpire(DateUtil.formatDate(orderExpirationTime, DateUtil.DATE_TIME_FORMAT));
        }
        //如果是测试环境并且是商城订单支付一分钱
        if (FundsConstant.test_profile.contains(active)&& !OrderTypeEnum.moreCredit.getCode().equals(orderPay.getOrderType())) {
            model.setTotalAmount(testPayAmount);
        }
        aliRequest.setBizModel(model);
        aliRequest.setNotifyUrl(aliPayConfig.getPayNotifyUrl());
        //新增支付宝调用记录
        OrderAliPay orderAliPay = new OrderAliPay();
        orderAliPay.setAppId(aliPayConfig.getAppId());
        orderAliPay.setMethod(aliPayConfig.getAppId());
        orderAliPay.setOutTradeNo(model.getOutTradeNo());
        orderAliPay.setTotalAmount(model.getTotalAmount());
        orderAliPay.setProduct(orderPay.getProduct());
        orderAliPay.setSubject(orderPay.getSubject());
        orderAliPay.setTimeExpire(orderPay.getExpirationTime());
        orderAliPay.setReturnUrl(aliRequest.getNotifyUrl());
        log.info("开始调用支付宝：aliRequest={}", JSON.toJSONString(aliRequest));
        try {
            AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(aliRequest);
            if (alipayTradeAppPayResponse.isSuccess()) {
                log.info("支付宝调用完成,response={}", JSON.toJSONString(alipayTradeAppPayResponse));
            }
            orderAliPay.setSubCode(alipayTradeAppPayResponse.getSubCode());
            orderAliPay.setCode(alipayTradeAppPayResponse.getCode());
            orderAliPay.setMerchantOrderNo(alipayTradeAppPayResponse.getMerchantOrderNo());
            orderAliPay.setSubMsg(alipayTradeAppPayResponse.getSubMsg());
            orderAliPay.setMsg(alipayTradeAppPayResponse.getMsg());
            orderAliPay.setBody(alipayTradeAppPayResponse.getBody());
            //返回支付宝订单信息(预处理)可以直接给APP请求，无需再做处理
            orderString = alipayTradeAppPayResponse.getBody();
        } catch (AlipayApiException e) {
            throw new PayException("调用支付宝", e);
        }finally {
            orderAliPayDao.insert(orderAliPay);
        }
        return orderString;
    }


    /**
     * 查询支付宝订单
     * @param orderAliPay
     * @throws AlipayApiException
     */
    public OrderAliPay queryOrderPayStatus(OrderAliPay orderAliPay) {
        //获取应用支付宝配置
        AliPayConfig aliPayConfig = aliPayConfigDao.getAliPayConfigByAppId(orderAliPay.getAppId());
        ParamException.isNull(aliPayConfig, "未找到该平台的支付宝配置信息");
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.QUERY_PAY_URL, aliPayConfig.getAppId(),aliPayConfig.getAppKey(), AlipayConstants.FORMAT_JSON,AlipayConstants.CHARSET_UTF8, aliPayConfig.getAliPub(), AlipayConstants.SIGN_TYPE_RSA2);
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizContent("{'out_trade_no':"+orderAliPay.getOutTradeNo()+"}");
        AlipayTradeQueryResponse response;
        try {
            log.info("查询支付宝订单 request={}",JSON.toJSONString(request));
            response = alipayClient.execute(request);
            log.info("查询支付宝订单返回数据 ={}",JSON.toJSONString(response));
            orderAliPay.setCode(response.getCode());
            orderAliPay.setSubMsg(response.getSubMsg());
            orderAliPay.setSubCode(response.getSubCode());
            orderAliPay.setMsg(response.getMsg());
            orderAliPay.setBuyerLogonId(response.getBuyerLogonId());
            orderAliPay.setBuyerPayAmount(response.getBuyerPayAmount());
            orderAliPay.setBuyerUserId(response.getBuyerUserId());
            if(response.getSendPayDate()!=null){
                orderAliPay.setSendPayDate(Instant.ofEpochMilli(response.getSendPayDate().getTime()));
            }
            orderAliPay.setInvoiceAmount(response.getInvoiceAmount());
            orderAliPay.setReceiptAmount(response.getReceiptAmount());
            orderAliPay.setTradeStatus(response.getTradeStatus());
            orderAliPayDao.updateByPrimaryKeySelective(orderAliPay);
            //只处理支付完成的订单
            if (paySuccess.equals(response.getTradeStatus())) {
                paymentServer.completePayment(orderAliPay.getAppId(),response.getOutTradeNo(),response.getTradeNo(), PaymentEnum.ALI_PAY.getCode(),orderAliPay.getId());
            }
        }catch (Exception e){
            log.error("查询支付宝交易订单异常",e);
        }
        return orderAliPay;
    }


    /**
     * 支付宝支付
     *
     * @param orderRefunds
     * @return
     */
    @Async
    @Transactional(rollbackFor = Exception.class,propagation= Propagation.NOT_SUPPORTED)
    public OrderAliPayRefunds refunds(OrderRefunds orderRefunds) {
        OrderAliPayRefunds aliPayRefunds = new OrderAliPayRefunds();
        //获取应用支付宝配置
        AliPayConfig aliPayConfig = aliPayConfigDao.getAliPayConfigByAppId(orderRefunds.getPayAppId());
        ParamException.isNull(aliPayConfig, "未找到该平台的支付宝配置信息");
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.QUERY_PAY_URL,aliPayConfig.getAppId(), aliPayConfig.getAppKey(), AlipayConstants.FORMAT_JSON, AlipayConstants.CHARSET_GBK,aliPayConfig.getAliPub(), AlipayConstants.SIGN_TYPE_RSA2);
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayRefundBo refundBo = new AlipayRefundBo();
        refundBo.setOut_trade_no(orderRefunds.getOrderNo());
        refundBo.setTrade_no(orderRefunds.getTransactionId());
        refundBo.setRefund_amount(orderRefunds.getRefundsAmount().setScale(2).toString());
        refundBo.setOut_request_no(orderRefunds.getId());
        if (FundsConstant.test_profile.contains(active)&& !OrderTypeEnum.moreCredit.getCode().equals(orderRefunds.getOrderType())) {
            refundBo.setRefund_amount("0.01");
        }
        request.setBizContent(JSON.toJSONString(refundBo));
        aliPayRefunds.setAppId(aliPayConfig.getAppId());
        aliPayRefunds.setMethod(request.getApiMethodName());
        aliPayRefunds.setOutTradeNo(orderRefunds.getOrderNo());
        aliPayRefunds.setRefundAmount(new BigDecimal(refundBo.getRefund_amount()));
        try {
            log.info("请求支付宝退款入参 response={}:", JSON.toJSONString(request));
            AlipayTradeRefundResponse response = alipayClient.execute(request);
            aliPayRefunds.setCode(response.getCode());
            aliPayRefunds.setMsg(response.getMsg());
            aliPayRefunds.setSubCode(response.getSubCode());
            aliPayRefunds.setSubMsg(response.getSubMsg());
            aliPayRefunds.setTradeNo(response.getTradeNo());
            aliPayRefunds.setRefundAmount(new BigDecimal(response.getRefundFee()));
            aliPayRefunds.setBuyerLogonId(response.getBuyerLogonId());
            aliPayRefunds.setBuyerUserId(response.getBuyerUserId());
            aliPayRefunds.setFundChange(response.getFundChange());
            aliPayRefunds.setRefundFee(response.getFundChange());
            log.info("调用支付宝退款返回数据 response={}:", JSON.toJSONString(response));
        } catch (Exception e) {
            log.error("支付宝退款失败", e);
        }finally {
            if(paySuccessCode.equals(aliPayRefunds.getCode())){
                orderRefunds.setStatus(OrderEnum.PayStatus.SUCCEED.getCode());
            }else {
                orderRefunds.setStatus(OrderEnum.PayStatus.FILL.getCode());
            }
            orderRefunds.setTransactionId(aliPayRefunds.getTradeNo());
            orderRefunds.setRefundsFlowId(aliPayRefunds.getId());
            orderRefunds.setErrMsg(aliPayRefunds.getSubMsg());
            orderRefundsDao.updateByPrimaryKeySelective(orderRefunds);
            if(StrUtil.isNotBlank(orderRefunds.getNotifyMethod())){
                rabbitTemplate.convertAndSend(orderRefunds.getNotifyMethod(),JSON.toJSONString(orderRefunds));
            }
            orderAliPayRefundsDao.insert(aliPayRefunds);
        }
        return aliPayRefunds;
    }


    /**
     * 支付宝异步请求逻辑处理
     *
     * @return
     */
    public String payNotify(Map<String, String> notifyParams) throws AlipayApiException {
        log.info("==================支付宝异步请求逻辑处理");
        //签名验证(对支付宝返回的数据验证，确定是支付宝返回的)
        boolean signVerified = AlipaySignature.rsaCheckV1(notifyParams, AlipayConfig.NOTIFY_PUBLIC_KEY, AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA2);
        //只处理成功的请求
        if (!paySuccess.equals(notifyParams.get("trade_status"))) {
            return "success";
        }
        //对验签进行处理
        if (signVerified) {
            OrderAliPay pay = orderAliPayDao.nowPay(notifyParams.get("out_trade_no"));
            pay.setBuyerLogonId(notifyParams.get("buyer_logon_id"));
            pay.setBuyerPayAmount(notifyParams.get("buyer_pay_amount"));
            pay.setBuyerUserId(notifyParams.get("buyer_user_id"));
            pay.setInvoiceAmount(notifyParams.get("invoice_amount"));
            pay.setReceiptAmount(notifyParams.get("receipt_amount"));
            pay.setTradeStatus(notifyParams.get("trade_status"));
            pay.setTradeNo(notifyParams.get("trade_no"));
            pay.setNotifyTime(Instant.now());
            pay.setAppId(pay.getAppId());
            if(pay==null){
                orderAliPayDao.insert(pay);
            }else {
                orderAliPayDao.updateByPrimaryKeySelective(pay);
            }
            if(paySuccess.equals(pay.getTradeStatus())){
                paymentServer.completePayment(pay.getAppId(),pay.getOutTradeNo(), pay.getTradeNo(), PaymentEnum.ALI_PAY.getCode(), pay.getId());
            }
        } else {
            log.error("==================验签不通过 ！notifyParams ={} ", notifyParams);
            return "fail";
        }
        return "success";
    }


    public void queryRefund(OrderRefunds orderRefunds){
        OrderAliPayRefunds orderAliPayRefunds = orderAliPayRefundsDao.selectByPrimaryKey(orderRefunds.getRefundsFlowId());
        if(orderAliPayRefunds==null){
            refunds(orderRefunds);
            return;
        }
        if(paySuccessCode.equals(orderAliPayRefunds.getCode())){
            orderRefunds.setStatus(OrderEnum.PayStatus.SUCCEED.getCode());
            orderRefunds.setTransactionId(orderAliPayRefunds.getTradeNo());
            orderRefunds.setRefundsFlowId(orderAliPayRefunds.getId());
            orderRefunds.setErrMsg(orderAliPayRefunds.getSubMsg());
            orderRefundsDao.updateByPrimaryKeySelective(orderRefunds);
            if(StrUtil.isNotBlank(orderRefunds.getNotifyMethod())){
                rabbitTemplate.convertAndSend(orderRefunds.getNotifyMethod(),JSON.toJSONString(orderRefunds));
            }
        }else {
            //获取应用支付宝配置
            AliPayConfig aliPayConfig = aliPayConfigDao.getAliPayConfigByAppId(orderRefunds.getPayAppId());
            AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.QUERY_PAY_URL,aliPayConfig.getAppId(),aliPayConfig.getAppKey(),AlipayConstants.FORMAT_JSON,AlipayConstants.CHARSET_GBK,aliPayConfig.getAliPub(),AlipayConstants.SIGN_TYPE_RSA2);
            AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
            request.setBizContent("{'out_request_no':"+ orderRefunds.getId()+ "}");
            try {
                AlipayTradeFastpayRefundQueryResponse response = alipayClient.execute(request);
                orderAliPayRefunds.setCode(response.getCode());
                orderAliPayRefunds.setMsg(response.getMsg());
                orderAliPayRefunds.setSubCode(response.getSubCode());
                orderAliPayRefunds.setSubMsg(response.getSubMsg());
                orderAliPayRefunds.setTradeNo(response.getTradeNo());
                orderAliPayRefunds.setRefundAmount(new BigDecimal(response.getRefundAmount()));
            }catch (AlipayApiException e){
                log.error("查询支付宝退款异常", e);
            }finally {
                if(paySuccessCode.equals(orderAliPayRefunds.getCode())){
                    orderRefunds.setStatus(OrderEnum.PayStatus.SUCCEED.getCode());
                }else {
                    orderRefunds.setStatus(OrderEnum.PayStatus.FILL.getCode());
                }
                if(StrUtil.isNotBlank(orderRefunds.getNotifyMethod())){
                    rabbitTemplate.convertAndSend(orderRefunds.getNotifyMethod(),JSON.toJSONString(orderRefunds));
                }
                orderRefundsDao.updateByPrimaryKeySelective(orderRefunds);
                orderAliPayRefundsDao.updateByPrimaryKeySelective(orderAliPayRefunds);
            }

        }
    }

}
